﻿/*----------------------------------------------------------------
// Copyright (C) 2016 苏州，顾宏
//
// 模块名：cfg_reader
// 创建者：Macro Gu
// 修改者列表：
// 创建日期：2016.1.5
// 模块描述：读配置类
//----------------------------------------------------------------*/
#include "cfg_reader.h"

#include "fmt.h"  // for Fmt()

#include <boost/algorithm/string.hpp>  // for trim_copy()
#include <fstream>  // for ifstream

CCfgReader::CCfgReader(const std::string& strFile)
:m_strFile(strFile), m_bScan(false)
{
}

CCfgReader::~CCfgReader()
{
	CfgDict::iterator iter = m_CfgDict.begin();
	for (; iter != m_CfgDict.end(); ++iter)
	{
		delete iter->second;
		iter->second = nullptr;
	}
}

std::string CCfgReader::GetValue(const char* szSection, const char* szName)
{
	if (!m_bScan)
	{
		ScanCfgFile();
	}

	CfgDict::const_iterator iter = m_CfgDict.find(szSection);
	if (iter != m_CfgDict.end())
	{
		std::map<string, string>& tmp = *(iter->second);
		std::map<string, string>::const_iterator iter2 = tmp.find(szName);
		if (iter2 != tmp.end())
		{
			//printf("get_value, section=[%s], %s=%s\n", szSection, szName, iter2->second.c_str());
			return iter2->second;
		}
	}

	throw (Fmt("Empty item value: [%s] %s!") % szSection % szName).str();
	static string strEmpty("");
	return strEmpty;
}

std::string CCfgReader::GetOptValue(const char* szSection, const char* szName,
		const string& strDefault)
{
	try
	{
		return GetValue(szSection, szName);
	}
	catch (...)
	{
		return strDefault;
	}
}

void CCfgReader::ScanCfgFile()
{
	std::ifstream file(m_strFile.c_str());
	if (!file.is_open())
		throw (Fmt("Failed to open config file: %s") % m_strFile).str();

	string strSection;
	char szLine[128];
	while (!file.eof() && file.getline(szLine, sizeof(szLine), 0x0A))
	{
		using boost::algorithm::trim_copy;
		//window文件格式换行是0x0D0A,UNIX/LINUX是0x0A
		string sLine = trim_copy(string(szLine));
		if (sLine.empty() || sLine[0] == '#')
		{
			continue;
		}

		if (sLine[0] == '[' && sLine[sLine.size() - 1] == ']')
		{
			strSection = sLine.substr(1, sLine.size() - 2);
			continue;
		}

		string::size_type pos = sLine.find("=");
		if (pos == string::npos)
		{
			continue;
		}

		if (strSection.empty())
			throw (Fmt("item '%s' has not section") % sLine).str();

		string strTemp = sLine.substr(0, pos);
		string s1 = trim_copy(strTemp);
		strTemp = sLine.substr(pos + 1, sLine.size() - pos - 1);
		string s2 = trim_copy(strTemp);

		CfgDict::iterator iter = m_CfgDict.lower_bound(strSection);
		if (iter != m_CfgDict.end() && strSection == iter->first)
		{
			iter->second->insert(make_pair(s1, s2));
		}
		else
		{
			std::map<string, string>* tmp = new std::map< string, string > ;
			tmp->insert(make_pair(s1, s2));
			m_CfgDict.insert(iter, make_pair(strSection, tmp));
		}
	}
	m_bScan = true;
}

